#ifdef __EOS__
#include <rtthread.h>
#include "irq_numbers.h"
#include "gpio/pinctrl.h"
#include "clk.h"
#include "config_api.h"
#else
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/types.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
#include <linux/pm_clock.h>
#include <linux/iio/iio.h>

#endif
#include "ei_common.h"
#include "ei_os.h"
#include "ei_comm_viss.h"
#include "ei_comm_camera.h"

#ifdef ARCH_LOMBO_N7V7
#ifdef CONFIG_LOMBO_DOUBLE_OS
#undef CONFIG_LOMBO_DOUBLE_OS
#endif
#endif

extern VISS_RESOURCE_S g_stVissSrc;

extern int VISS_ModInit(void);
extern void VISS_ModExit(void);
extern EI_S32 VISS_Suspend(void);
extern EI_S32 VISS_Resume(void);

extern int VISS_MCSI_IrqHandler(int irq, void *priv);
extern int VISS_VIC_IrqHandler(int irq, void *priv);
extern int VISS_WB_DMA_IrqHandler(int irq, void *priv);

#define VIC_FREQ                (1485 * 100 * 1000)
#define MCSI_FREQ               (1485 * 100 * 1000)

#ifdef __EOS__
typedef struct eiVISS_DEV_S {
    EI_U32                      u32Freq;
    EI_S32                      s32MdId;
    EI_U32                      u32DevId;
    EI_S32                      s32I2cBus;
    EI_S32                      s32I2cAddr;
    EI_U32                      u32Pwdn[SNS_PWR_ACT_MAX];
    EI_U32                      u32Rst[SNS_PWR_ACT_MAX];
    EI_U32                      u32Mclk[SNS_PWR_ACT_MAX];
    EI_U32                      u32Cam_en0[SNS_PWR_ACT_MAX];
    EI_U32                      u32Cam_en1[SNS_PWR_ACT_MAX];
    EI_U32                      u32Cam_en2[SNS_PWR_ACT_MAX];
    struct pinctrl             *stPinCtrl;
    EI_U32                      s32Pin[SNS_PWR_ACT_MAX][7];
    VISS_DEV_TYPE_E             enDevType;
    EI_U32                      u32mclk;
    EI_U32                      u32Irqno;
    EI_U32                      u32SnsMirror;
    EI_U32                      u32SnsFlip;
} VISS_DEV_S;
#define VISS_MAX_SRCCLKS        (2)
typedef struct eiVISS_SCLK_S {
	const char *viss_sclk;
	const char *parrent;
} VISS_SCLK_S;

struct eiVISS_CLK {
	VISS_SCLK_S sclk[VISS_MAX_SRCCLKS];
	const char *viss_reset;
	const char *viss_gate;
	const char *viss_axi_gate;
};

static const struct eiVISS_CLK vclk = {
	.sclk = {
		{
			.viss_sclk = CLK_NAME_VISS_SCLK0,
			.parrent = CLK_NAME_PERH0_PLL_DIV2,
		},
		{
			.viss_sclk = CLK_NAME_VISS_SCLK2,
			.parrent =  CLK_NAME_OSC24M,
		},
	},
	.viss_reset = CLK_NAME_AHB_VISS_RESET,
	.viss_gate = CLK_NAME_AHB_VISS_GATE,
	.viss_axi_gate = CLK_NAME_MAXI_VISS_GATE,
#if 0
#if defined(ARCH_LOMBO_N7V3) || defined(ARCH_LOMBO_N7V5)
	.viss_axi_gate = CLK_NAME_MAXI_VISS_GATE,
#else
	.viss_axi_gate = CLK_NAME_MAXI_VISS0_GATE,
#endif
#endif
};

#define VBASE_VISS 0x01400000
#define VBASE_VIC  0x01410000
#define VBASE_MIPI0 0x01414000
/* #define VBASE_MIPI2 0x01418000 */
#define VBASE_WB_DMA 0x01430000
#define VISS_MODULE_NAME "ei_viss"
#define VISS_VIC_NAME "ei_vic"
#define VISS_MIPI0_NAME "ei_mipi0"
#define VISS_MIPI1_NAME "ei_mipi2"
#define VISS_WB_DMA_NAME "ei_wb_dma"
#define MIPI0_GPIO_GROUP "mcsi0-grp"
#define VIC_GPIO_GROUP	"vic-grp"
#define MIPI1_GPIO_GROUP "mcsi1-grp"
#define VISS_VIC_MODULE_ID (0)

#if defined ARCH_LOMBO_N7V3
#define VISS_MIPI0_MODULE_ID (2)
#define VISS_MIPI1_MODULE_ID (4)
#define VBASE_MIPI2 0x01418000
#elif defined ARCH_LOMBO_N7V7
#define VISS_MIPI0_MODULE_ID (2)
#define VISS_MIPI1_MODULE_ID (3)
#define VBASE_MIPI2 0x01416000
#endif


VISS_DEV_S viss_pin_dev[VISS_MAX_DEV_NUM];

void viss_md_top_clk_init(void)
{
	int i = 0;
	clk_handle_t chld = 0, self = 0, parrent = 0;
	/* csp_viss_top_set_register_base((void *)(0x01400000 + 0x0)); */

	chld = clk_get(vclk.viss_reset);
	clk_enable(chld);
	chld = clk_get(vclk.viss_gate);
	clk_enable(chld);
	chld = clk_get(vclk.viss_axi_gate);
	clk_enable(chld);
	for (i = 0; i < VISS_MAX_SRCCLKS; i++) {
		if (RT_NULL != vclk.sclk[i].viss_sclk) {
			self = clk_get(vclk.sclk[i].viss_sclk);
			parrent = clk_get(vclk.sclk[i].parrent);
			clk_set_parent(self, parrent);
			clk_enable(self);
		}
	}
}

void viss_md_top_clk_exit(void)
{
	clk_handle_t chld = 0;
	int i = 0;
	chld = clk_get(vclk.viss_reset);
	clk_disable(chld);
	chld = clk_get(vclk.viss_gate);
	clk_disable(chld);
	chld = clk_get(vclk.viss_axi_gate);
	clk_disable(chld);
	for (i = 0; i < VISS_MAX_SRCCLKS; i++) {
		if (RT_NULL != vclk.sclk[i].viss_sclk) {
			chld = clk_get(vclk.sclk[i].viss_sclk);
			clk_disable(chld);
		}
	}
}

int VISS_DEV_SetPinState(VISS_DEV dev,  CAMERA_POWER_ACT_S *pAct)
{
    VISS_DEV_S *csi = &viss_pin_dev[dev];

    if (pAct->u8Act > SNS_DELAY - 1) {
        PRT_VISS_ERR("pAct->u8Act err\n");
        return EI_FAILURE;
    }

    if (csi->s32Pin[pAct->u8Act][0] == -1) {
        switch (pAct->u8Act) {
            case SNS_RESET:
                PRT_VISS_WARN("dev:%d NO SNS_RESET PIN\n", dev);
                break;
            case SNS_PWDN:
                PRT_VISS_WARN("dev:%d NO SNS_PWDN PIN\n", dev);
                break;
            case SNS_IR_RESET:
                PRT_VISS_WARN("dev:%d NO SNS_IR_RESET PIN\n", dev);
                break;
            case SNS_IR_PWDN:
                PRT_VISS_WARN("dev:%d NO SNS_IR_PWDN PIN\n", dev);
                break;
            case MS_RESET:
                PRT_VISS_WARN("dev:%d NO MS_RESET PIN\n", dev);
                break;
            case MS_VD_FZ:
                PRT_VISS_WARN("dev:%d NO MS_VD_FZ PIN\n", dev);
                break;
            case CAM_EN:
                PRT_VISS_WARN("dev:%d NO CAM_EN PIN\n", dev);
                break;

            default:
                PRT_VISS_ERR("pAct->u8Act err\n");
        }
        return EI_SUCCESS;
    }

    if ( (pAct->u8Act % 2) == 0)
        pinctrl_gpio_set_value(csi->stPinCtrl, csi->u32Rst[pAct->u8Act], pAct->u8Ud);
    else
        pinctrl_gpio_set_value(csi->stPinCtrl, csi->u32Pwdn[pAct->u8Act], pAct->u8Ud);

    return EI_SUCCESS;
}

static int ei_viss_ms_reques_pins(VISS_DEV_S *vic, const EI_CHAR *module)
{
    int ret = 0;

    ret = config_get_u32_array(module, "ms_vd_fz_pin",
		vic->s32Pin[MS_VD_FZ], ARRAY_SIZE(vic->s32Pin[MS_VD_FZ]));
    if (ret != ARRAY_SIZE(vic->s32Pin[MS_VD_FZ])) {
         os_printk("no pwdn pin for ms%d pwdn\n", vic->u32DevId);
         vic->s32Pin[MS_VD_FZ][0] = -1;
    } else {
         vic->u32Pwdn[MS_VD_FZ] = pinctrl_gpio_request(vic->stPinCtrl,
		vic->s32Pin[MS_VD_FZ][0], vic->s32Pin[MS_VD_FZ][1]);
         if (vic->u32Pwdn[MS_VD_FZ] >= 0) {

             pinctrl_gpio_set_function(vic->stPinCtrl, vic->u32Pwdn[MS_VD_FZ],
                    vic->s32Pin[MS_VD_FZ][2]);
             pinctrl_gpio_set_drv_level(vic->stPinCtrl, vic->u32Pwdn[MS_VD_FZ],
                    vic->s32Pin[MS_VD_FZ][3]);
             pinctrl_gpio_set_pud_mode(vic->stPinCtrl, vic->u32Pwdn[MS_VD_FZ],
                    vic->s32Pin[MS_VD_FZ][4]);
             pinctrl_gpio_set_pud_res(vic->stPinCtrl, vic->u32Pwdn[MS_VD_FZ],
                    vic->s32Pin[MS_VD_FZ][5]);
             pinctrl_gpio_set_value(vic->stPinCtrl, vic->u32Pwdn[MS_VD_FZ],
                    vic->s32Pin[MS_VD_FZ][6]);
        }

    }


    /* reset pin */
    ret = config_get_u32_array(module, "ms_reset_pin",
            vic->s32Pin[MS_RESET], ARRAY_SIZE(vic->s32Pin[MS_RESET]));
    if (ret != ARRAY_SIZE(vic->s32Pin[MS_RESET])) {
         os_printk("no reset pin for ms%d reset\n", vic->u32DevId);
         vic->s32Pin[MS_RESET][0] = -1;
    } else {
         vic->u32Rst[MS_RESET] = pinctrl_gpio_request(vic->stPinCtrl,
			vic->s32Pin[MS_RESET][0], vic->s32Pin[MS_RESET][1]);
         if (vic->u32Rst[MS_RESET] >= 0) {

             pinctrl_gpio_set_function(vic->stPinCtrl, vic->u32Rst[MS_RESET],
                     vic->s32Pin[MS_RESET][2]);
             pinctrl_gpio_set_drv_level(vic->stPinCtrl, vic->u32Rst[MS_RESET],
                     vic->s32Pin[MS_RESET][3]);
             pinctrl_gpio_set_pud_mode(vic->stPinCtrl, vic->u32Rst[MS_RESET],
                     vic->s32Pin[MS_RESET][4]);
             pinctrl_gpio_set_pud_res(vic->stPinCtrl, vic->u32Rst[MS_RESET],
                     vic->s32Pin[MS_RESET][5]);
             pinctrl_gpio_set_value(vic->stPinCtrl, vic->u32Rst[MS_RESET],
                     vic->s32Pin[MS_RESET][6]);
        }

    }

    return 0;
}

static int ei_viss_ir_reques_pins(VISS_DEV_S *vic, const EI_CHAR *module)
{
    int ret = 0;

    ret = config_get_u32_array(module, "ir_pwdn_pin",
		vic->s32Pin[SNS_IR_PWDN], ARRAY_SIZE(vic->s32Pin[SNS_IR_PWDN]));
    if (ret != ARRAY_SIZE(vic->s32Pin[SNS_IR_PWDN])) {
         os_printk("no pwdn pin for ir%d pwdn\n", vic->u32DevId);
         vic->s32Pin[SNS_IR_PWDN][0] = -1;
    } else {
         vic->u32Pwdn[SNS_IR_PWDN] = pinctrl_gpio_request(vic->stPinCtrl,
			vic->s32Pin[SNS_IR_PWDN][0], vic->s32Pin[SNS_IR_PWDN][1]);
         if (vic->u32Pwdn[SNS_IR_PWDN] >= 0) {

             pinctrl_gpio_set_function(vic->stPinCtrl, vic->u32Pwdn[SNS_IR_PWDN],
                     vic->s32Pin[SNS_IR_PWDN][2]);
             pinctrl_gpio_set_drv_level(vic->stPinCtrl, vic->u32Pwdn[SNS_IR_PWDN],
                     vic->s32Pin[SNS_IR_PWDN][3]);
             pinctrl_gpio_set_pud_mode(vic->stPinCtrl, vic->u32Pwdn[SNS_IR_PWDN],
                     vic->s32Pin[SNS_IR_PWDN][4]);
             pinctrl_gpio_set_pud_res(vic->stPinCtrl, vic->u32Pwdn[SNS_IR_PWDN],
                     vic->s32Pin[SNS_IR_PWDN][5]);
             pinctrl_gpio_set_value(vic->stPinCtrl, vic->u32Pwdn[SNS_IR_PWDN],
                     vic->s32Pin[SNS_IR_PWDN][6]);
        }

    }


    /* reset pin */
    ret = config_get_u32_array(module, "ir_reset_pin",
          vic->s32Pin[SNS_IR_RESET], ARRAY_SIZE(vic->s32Pin[SNS_IR_RESET]));
    if (ret != ARRAY_SIZE(vic->s32Pin[SNS_IR_RESET])) {
         os_printk("no reset pin for ir%d reset\n", vic->u32DevId);
         vic->s32Pin[SNS_IR_RESET][0] = -1;
    } else {
         vic->u32Rst[SNS_IR_RESET] = pinctrl_gpio_request(vic->stPinCtrl,
			vic->s32Pin[SNS_IR_RESET][0], vic->s32Pin[SNS_IR_RESET][1]);
         if (vic->u32Rst[SNS_IR_RESET] >= 0) {

             pinctrl_gpio_set_function(vic->stPinCtrl, vic->u32Rst[SNS_IR_RESET],
                     vic->s32Pin[SNS_IR_RESET][2]);
             pinctrl_gpio_set_drv_level(vic->stPinCtrl, vic->u32Rst[SNS_IR_RESET],
                     vic->s32Pin[SNS_IR_RESET][3]);
             pinctrl_gpio_set_pud_mode(vic->stPinCtrl, vic->u32Rst[SNS_IR_RESET],
                     vic->s32Pin[SNS_IR_RESET][4]);
             pinctrl_gpio_set_pud_res(vic->stPinCtrl, vic->u32Rst[SNS_IR_RESET],
                     vic->s32Pin[SNS_IR_RESET][5]);
             pinctrl_gpio_set_value(vic->stPinCtrl, vic->u32Rst[SNS_IR_RESET],
                     vic->s32Pin[SNS_IR_RESET][6]);
        }

    }

    return 0;
}

static int ei_viss_mcsi_reques_pins(VISS_DEV_S *mcsi, const EI_CHAR *module)
{
    int ret = 0;

    mcsi->s32Pin[CAM_EN][0] = -1;
    ret = config_get_u32_array(module, "mcsi_pwdn_pin",
		mcsi->s32Pin[SNS_PWDN], ARRAY_SIZE(mcsi->s32Pin[SNS_PWDN]));
    if (ret != ARRAY_SIZE(mcsi->s32Pin[SNS_PWDN])) {
         os_printk("no pwdn pin for mcsi%d pwdn\n", mcsi->u32DevId);
         mcsi->s32Pin[SNS_PWDN][0] = -1;
    } else {
         mcsi->u32Pwdn[SNS_PWDN] = pinctrl_gpio_request(mcsi->stPinCtrl,
		mcsi->s32Pin[SNS_PWDN][0], mcsi->s32Pin[SNS_PWDN][1]);
         if (mcsi->u32Pwdn[SNS_PWDN] >= 0) {
             pinctrl_gpio_set_function(mcsi->stPinCtrl, mcsi->u32Pwdn[SNS_PWDN],
                     mcsi->s32Pin[SNS_PWDN][2]);
             pinctrl_gpio_set_drv_level(mcsi->stPinCtrl, mcsi->u32Pwdn[SNS_PWDN],
                     mcsi->s32Pin[SNS_PWDN][3]);
             pinctrl_gpio_set_pud_mode(mcsi->stPinCtrl, mcsi->u32Pwdn[SNS_PWDN],
                     mcsi->s32Pin[SNS_PWDN][4]);
             pinctrl_gpio_set_pud_res(mcsi->stPinCtrl, mcsi->u32Pwdn[SNS_PWDN],
                     mcsi->s32Pin[SNS_PWDN][5]);
             pinctrl_gpio_set_value(mcsi->stPinCtrl, mcsi->u32Pwdn[SNS_PWDN],
                     mcsi->s32Pin[SNS_PWDN][6]);
        }

    }


    /* reset pin */
    ret = config_get_u32_array(module, "mcsi_reset_pin",
              mcsi->s32Pin[SNS_RESET], ARRAY_SIZE(mcsi->s32Pin[SNS_RESET]));
    if (ret != ARRAY_SIZE(mcsi->s32Pin[SNS_RESET])) {
         os_printk("no reset pin for mcsi%d reset\n", mcsi->u32DevId);
         mcsi->s32Pin[SNS_RESET][0] = -1;
    } else {
         mcsi->u32Rst[SNS_RESET] = pinctrl_gpio_request(mcsi->stPinCtrl,
		mcsi->s32Pin[SNS_RESET][0], mcsi->s32Pin[SNS_RESET][1]);
         if (mcsi->u32Rst[SNS_RESET] >= 0) {

             pinctrl_gpio_set_function(mcsi->stPinCtrl, mcsi->u32Rst[SNS_RESET],
                     mcsi->s32Pin[SNS_RESET][2]);
             pinctrl_gpio_set_drv_level(mcsi->stPinCtrl, mcsi->u32Rst[SNS_RESET],
                     mcsi->s32Pin[SNS_RESET][3]);
             pinctrl_gpio_set_pud_mode(mcsi->stPinCtrl, mcsi->u32Rst[SNS_RESET],
                     mcsi->s32Pin[SNS_RESET][4]);
             pinctrl_gpio_set_pud_res(mcsi->stPinCtrl, mcsi->u32Rst[SNS_RESET],
                     mcsi->s32Pin[SNS_RESET][5]);
             pinctrl_gpio_set_value(mcsi->stPinCtrl, mcsi->u32Rst[SNS_RESET],
                     mcsi->s32Pin[SNS_RESET][6]);
        }

    }


    /* mclk pin */
    ret = config_get_u32_array(module, "mcsi_mclk_pin",
          mcsi->s32Pin[SNS_MCLK], ARRAY_SIZE(mcsi->s32Pin[SNS_MCLK]));
    if (ret != ARRAY_SIZE(mcsi->s32Pin[SNS_MCLK])) {
    	os_printk("no mclk pin for mcsi%d mclk\n", mcsi->u32DevId);
    	mcsi->s32Pin[SNS_MCLK][0] = -1;
    } else {
         mcsi->u32Mclk[SNS_MCLK] = pinctrl_gpio_request(mcsi->stPinCtrl,
		mcsi->s32Pin[SNS_MCLK][0], mcsi->s32Pin[SNS_MCLK][1]);
         if (mcsi->u32Mclk[SNS_MCLK] >= 0) {
#if defined ARCH_LOMBO_N7V7

             if ((mcsi->u32Mclk[SNS_MCLK] == 12/* gpb 6 */) ||
                (mcsi->u32Mclk[SNS_MCLK] == 37/* gpc 24 */) ||
                (mcsi->u32Mclk[SNS_MCLK] == 71/* gpf 1 */))
                g_stVissSrc.useHfclkFlag[mcsi->u32DevId] = EI_TRUE;
             else
                g_stVissSrc.useHfclkFlag[mcsi->u32DevId] = EI_FALSE;
#endif

             pinctrl_gpio_set_function(mcsi->stPinCtrl, mcsi->u32Mclk[SNS_MCLK],
                     mcsi->s32Pin[SNS_MCLK][2]);
             pinctrl_gpio_set_drv_level(mcsi->stPinCtrl, mcsi->u32Mclk[SNS_MCLK],
                     mcsi->s32Pin[SNS_MCLK][3]);
             pinctrl_gpio_set_pud_mode(mcsi->stPinCtrl, mcsi->u32Mclk[SNS_MCLK],
                     mcsi->s32Pin[SNS_MCLK][4]);
             pinctrl_gpio_set_pud_res(mcsi->stPinCtrl, mcsi->u32Mclk[SNS_MCLK],
                     mcsi->s32Pin[SNS_MCLK][5]);
             pinctrl_gpio_set_value(mcsi->stPinCtrl, mcsi->u32Mclk[SNS_MCLK],
                     mcsi->s32Pin[SNS_MCLK][6]);
        }

    }

    /* cam_en pin */
    ret = config_get_u32_array(module, "cam_pwr0_pin",
          mcsi->s32Pin[VCC_EN0], ARRAY_SIZE(mcsi->s32Pin[VCC_EN0]));
    if (ret != ARRAY_SIZE(mcsi->s32Pin[VCC_EN0])) {
    	os_printk("no cam_pwr pin for mcsi%d cam_pwr0_pin\n", mcsi->u32DevId);
    	mcsi->s32Pin[VCC_EN0][0] = -1;
    } else {
         mcsi->u32Cam_en0[VCC_EN0] = pinctrl_gpio_request(mcsi->stPinCtrl,
		mcsi->s32Pin[VCC_EN0][0], mcsi->s32Pin[VCC_EN0][1]);
         if (mcsi->u32Cam_en0[VCC_EN0] >= 0) {
             pinctrl_gpio_set_function(mcsi->stPinCtrl, mcsi->u32Cam_en0[VCC_EN0],
                     mcsi->s32Pin[VCC_EN0][2]);
             pinctrl_gpio_set_drv_level(mcsi->stPinCtrl, mcsi->u32Cam_en0[VCC_EN0],
                     mcsi->s32Pin[VCC_EN0][3]);
             pinctrl_gpio_set_pud_mode(mcsi->stPinCtrl, mcsi->u32Cam_en0[VCC_EN0],
                     mcsi->s32Pin[VCC_EN0][4]);
             pinctrl_gpio_set_pud_res(mcsi->stPinCtrl, mcsi->u32Cam_en0[VCC_EN0],
                     mcsi->s32Pin[VCC_EN0][5]);
             pinctrl_gpio_set_value(mcsi->stPinCtrl, mcsi->u32Cam_en0[VCC_EN0],
                     mcsi->s32Pin[VCC_EN0][6]);
        }

    }

    ret = config_get_u32_array(module, "cam_pwr1_pin",
          mcsi->s32Pin[VCC_EN1], ARRAY_SIZE(mcsi->s32Pin[VCC_EN1]));
    if (ret != ARRAY_SIZE(mcsi->s32Pin[VCC_EN1])) {
    	os_printk("no cam_pwr pin for mcsi%d cam_pwr1_pin\n", mcsi->u32DevId);
    	mcsi->s32Pin[VCC_EN1][0] = -1;
    } else {
         mcsi->u32Cam_en1[VCC_EN1] = pinctrl_gpio_request(mcsi->stPinCtrl,
		mcsi->s32Pin[VCC_EN1][0], mcsi->s32Pin[VCC_EN1][1]);
         if (mcsi->u32Cam_en1[VCC_EN1] >= 0) {
             pinctrl_gpio_set_function(mcsi->stPinCtrl, mcsi->u32Cam_en1[VCC_EN1],
                     mcsi->s32Pin[VCC_EN1][2]);
             pinctrl_gpio_set_drv_level(mcsi->stPinCtrl, mcsi->u32Cam_en1[VCC_EN1],
                     mcsi->s32Pin[VCC_EN1][3]);
             pinctrl_gpio_set_pud_mode(mcsi->stPinCtrl, mcsi->u32Cam_en1[VCC_EN1],
                     mcsi->s32Pin[VCC_EN1][4]);
             pinctrl_gpio_set_pud_res(mcsi->stPinCtrl, mcsi->u32Cam_en1[VCC_EN1],
                     mcsi->s32Pin[VCC_EN1][5]);
             pinctrl_gpio_set_value(mcsi->stPinCtrl, mcsi->u32Cam_en1[VCC_EN1],
                     mcsi->s32Pin[VCC_EN1][6]);
        }

    }

    ret = config_get_u32_array(module, "cam_pwr2_pin",
          mcsi->s32Pin[VCC_EN2], ARRAY_SIZE(mcsi->s32Pin[VCC_EN2]));
    if (ret != ARRAY_SIZE(mcsi->s32Pin[VCC_EN2])) {
    	os_printk("no cam_pwr pin for mcsi%d cam_pwr2_pin\n", mcsi->u32DevId);
    	mcsi->s32Pin[VCC_EN2][0] = -1;
    } else {
         mcsi->u32Cam_en2[VCC_EN2] = pinctrl_gpio_request(mcsi->stPinCtrl,
		mcsi->s32Pin[VCC_EN2][0], mcsi->s32Pin[VCC_EN2][1]);
         if (mcsi->u32Cam_en2[VCC_EN2] >= 0) {
             pinctrl_gpio_set_function(mcsi->stPinCtrl, mcsi->u32Cam_en2[VCC_EN2],
                     mcsi->s32Pin[VCC_EN2][2]);
             pinctrl_gpio_set_drv_level(mcsi->stPinCtrl, mcsi->u32Cam_en2[VCC_EN2],
                     mcsi->s32Pin[VCC_EN2][3]);
             pinctrl_gpio_set_pud_mode(mcsi->stPinCtrl, mcsi->u32Cam_en2[VCC_EN2],
                     mcsi->s32Pin[VCC_EN2][4]);
             pinctrl_gpio_set_pud_res(mcsi->stPinCtrl, mcsi->u32Cam_en2[VCC_EN2],
                     mcsi->s32Pin[VCC_EN2][5]);
             pinctrl_gpio_set_value(mcsi->stPinCtrl, mcsi->u32Cam_en2[VCC_EN2],
                     mcsi->s32Pin[VCC_EN2][6]);
        }

    }

    return 0;
}
static int ei_viss_vic_reques_pins(VISS_DEV_S *vic, const EI_CHAR *module)
{
    int ret = 0;

    vic->s32Pin[CAM_EN][0] = -1;
    ret = config_get_u32_array(module, "dvp_pwdn_pin",
		vic->s32Pin[SNS_PWDN], ARRAY_SIZE(vic->s32Pin[SNS_PWDN]));
    if (ret != ARRAY_SIZE(vic->s32Pin[SNS_PWDN])) {
         os_printk("no pwdn pin for dvp%d pwdn\n", vic->u32DevId);
         vic->s32Pin[SNS_PWDN][0] = -1;
    } else {
         vic->u32Pwdn[SNS_PWDN] = pinctrl_gpio_request(vic->stPinCtrl,
              vic->s32Pin[SNS_PWDN][0], vic->s32Pin[SNS_PWDN][1]);
         if (vic->u32Pwdn[SNS_PWDN] >= 0) {
             pinctrl_gpio_set_function(vic->stPinCtrl, vic->u32Pwdn[SNS_PWDN],
                     vic->s32Pin[SNS_PWDN][2]);
             pinctrl_gpio_set_drv_level(vic->stPinCtrl, vic->u32Pwdn[SNS_PWDN],
                     vic->s32Pin[SNS_PWDN][3]);
             pinctrl_gpio_set_pud_mode(vic->stPinCtrl, vic->u32Pwdn[SNS_PWDN],
                     vic->s32Pin[SNS_PWDN][4]);
             pinctrl_gpio_set_pud_res(vic->stPinCtrl, vic->u32Pwdn[SNS_PWDN],
                     vic->s32Pin[SNS_PWDN][5]);
             pinctrl_gpio_set_value(vic->stPinCtrl, vic->u32Pwdn[SNS_PWDN],
                     vic->s32Pin[SNS_PWDN][6]);
        }

    }


    /* reset pin */
    ret = config_get_u32_array(module, "dvp_reset_pin",
           vic->s32Pin[SNS_RESET], ARRAY_SIZE(vic->s32Pin[SNS_RESET]));
    if (ret != ARRAY_SIZE(vic->s32Pin[SNS_RESET])) {
         os_printk("no reset pin for dvp%d reset\n", vic->u32DevId);
         vic->s32Pin[SNS_RESET][0] = -1;
    } else {
         vic->u32Rst[SNS_RESET] = pinctrl_gpio_request(vic->stPinCtrl,
              vic->s32Pin[SNS_RESET][0], vic->s32Pin[SNS_RESET][1]);
         if (vic->u32Rst[SNS_RESET] >= 0) {

             pinctrl_gpio_set_function(vic->stPinCtrl, vic->u32Rst[SNS_RESET],
                     vic->s32Pin[SNS_RESET][2]);
             pinctrl_gpio_set_drv_level(vic->stPinCtrl, vic->u32Rst[SNS_RESET],
                     vic->s32Pin[SNS_RESET][3]);
             pinctrl_gpio_set_pud_mode(vic->stPinCtrl, vic->u32Rst[SNS_RESET],
                     vic->s32Pin[SNS_RESET][4]);
             pinctrl_gpio_set_pud_res(vic->stPinCtrl, vic->u32Rst[SNS_RESET],
                     vic->s32Pin[SNS_RESET][5]);
             pinctrl_gpio_set_value(vic->stPinCtrl, vic->u32Rst[SNS_RESET],
                     vic->s32Pin[SNS_RESET][6]);
        }

    }

    /* mclk pin */
    ret = config_get_u32_array(module, "dvp_mclk_pin",
            vic->s32Pin[SNS_MCLK], ARRAY_SIZE(vic->s32Pin[SNS_MCLK]));
    if (ret != ARRAY_SIZE(vic->s32Pin[SNS_MCLK])) {
    	os_printk("no mclk pin for dvp%d mclk\n", vic->u32DevId);
    	vic->s32Pin[SNS_MCLK][0] = -1;
    } else {
         vic->u32Mclk[SNS_MCLK] = pinctrl_gpio_request(vic->stPinCtrl,
		vic->s32Pin[SNS_MCLK][0], vic->s32Pin[SNS_MCLK][1]);
         if (vic->u32Mclk[SNS_MCLK] >= 0) {
#if defined ARCH_LOMBO_N7V7
             if ((vic->u32Mclk[SNS_MCLK] == 12/* gpb 6 */) ||
                (vic->u32Mclk[SNS_MCLK] == 37/* gpc 24 */) ||
                (vic->u32Mclk[SNS_MCLK] == 71/* gpf 1 */))
                g_stVissSrc.useHfclkFlag[vic->u32DevId] = EI_TRUE;
             else
                g_stVissSrc.useHfclkFlag[vic->u32DevId] = EI_FALSE;
#endif

             pinctrl_gpio_set_function(vic->stPinCtrl, vic->u32Mclk[SNS_MCLK],
                     vic->s32Pin[SNS_MCLK][2]);
             pinctrl_gpio_set_drv_level(vic->stPinCtrl, vic->u32Mclk[SNS_MCLK],
                     vic->s32Pin[SNS_MCLK][3]);
             pinctrl_gpio_set_pud_mode(vic->stPinCtrl, vic->u32Mclk[SNS_MCLK],
                     vic->s32Pin[SNS_MCLK][4]);
             pinctrl_gpio_set_pud_res(vic->stPinCtrl, vic->u32Mclk[SNS_MCLK],
                     vic->s32Pin[SNS_MCLK][5]);
             pinctrl_gpio_set_value(vic->stPinCtrl, vic->u32Mclk[SNS_MCLK],
                     vic->s32Pin[SNS_MCLK][6]);
        }

    }

    /* cam_en pin */
    ret = config_get_u32_array(module, "cam_pwr0_pin",
            vic->s32Pin[VCC_EN0], ARRAY_SIZE(vic->s32Pin[VCC_EN0]));
    if (ret != ARRAY_SIZE(vic->s32Pin[VCC_EN0])) {
    	os_printk("no cam_pwr pin for dvp%d cam_pwr0_pin\n", vic->u32DevId);
    	vic->s32Pin[VCC_EN0][0] = -1;
    } else {
         vic->u32Cam_en0[VCC_EN0] = pinctrl_gpio_request(vic->stPinCtrl,
		vic->s32Pin[VCC_EN0][0], vic->s32Pin[VCC_EN0][1]);
         if (vic->u32Cam_en0[VCC_EN0] >= 0) {

             pinctrl_gpio_set_function(vic->stPinCtrl, vic->u32Cam_en0[VCC_EN0],
                     vic->s32Pin[VCC_EN0][2]);
             pinctrl_gpio_set_drv_level(vic->stPinCtrl, vic->u32Cam_en0[VCC_EN0],
                     vic->s32Pin[VCC_EN0][3]);
             pinctrl_gpio_set_pud_mode(vic->stPinCtrl, vic->u32Cam_en0[VCC_EN0],
                     vic->s32Pin[VCC_EN0][4]);
             pinctrl_gpio_set_pud_res(vic->stPinCtrl, vic->u32Cam_en0[VCC_EN0],
                     vic->s32Pin[VCC_EN0][5]);
             pinctrl_gpio_set_value(vic->stPinCtrl, vic->u32Cam_en0[VCC_EN0],
                     vic->s32Pin[VCC_EN0][6]);
        }

    }

    ret = config_get_u32_array(module, "cam_pwr1_pin",
            vic->s32Pin[VCC_EN1], ARRAY_SIZE(vic->s32Pin[VCC_EN1]));
    if (ret != ARRAY_SIZE(vic->s32Pin[VCC_EN1])) {
    	os_printk("no cam_pwr pin for dvp%d cam_pwr1_pin\n", vic->u32DevId);
    	vic->s32Pin[VCC_EN1][0] = -1;
    } else {
         vic->u32Cam_en1[VCC_EN1] = pinctrl_gpio_request(vic->stPinCtrl,
		vic->s32Pin[VCC_EN1][0], vic->s32Pin[VCC_EN1][1]);
         if (vic->u32Cam_en1[VCC_EN1] >= 0) {

             pinctrl_gpio_set_function(vic->stPinCtrl, vic->u32Cam_en1[VCC_EN1],
                     vic->s32Pin[VCC_EN1][2]);
             pinctrl_gpio_set_drv_level(vic->stPinCtrl, vic->u32Cam_en1[VCC_EN1],
                     vic->s32Pin[VCC_EN1][3]);
             pinctrl_gpio_set_pud_mode(vic->stPinCtrl, vic->u32Cam_en1[VCC_EN1],
                     vic->s32Pin[VCC_EN1][4]);
             pinctrl_gpio_set_pud_res(vic->stPinCtrl, vic->u32Cam_en1[VCC_EN1],
                     vic->s32Pin[VCC_EN1][5]);
             pinctrl_gpio_set_value(vic->stPinCtrl, vic->u32Cam_en1[VCC_EN1],
                     vic->s32Pin[VCC_EN1][6]);
        }

    }

    ret = config_get_u32_array(module, "cam_pwr2_pin",
            vic->s32Pin[VCC_EN2], ARRAY_SIZE(vic->s32Pin[VCC_EN2]));
    if (ret != ARRAY_SIZE(vic->s32Pin[VCC_EN2])) {
    	os_printk("no cam_pwr pin for dvp%d cam_pwr2_pin\n", vic->u32DevId);
    	vic->s32Pin[VCC_EN2][0] = -1;
    } else {
         vic->u32Cam_en2[VCC_EN2] = pinctrl_gpio_request(vic->stPinCtrl,
		vic->s32Pin[VCC_EN2][0], vic->s32Pin[VCC_EN2][1]);
         if (vic->u32Cam_en2[VCC_EN2] >= 0) {

             pinctrl_gpio_set_function(vic->stPinCtrl, vic->u32Cam_en2[VCC_EN2],
                     vic->s32Pin[VCC_EN2][2]);
             pinctrl_gpio_set_drv_level(vic->stPinCtrl, vic->u32Cam_en2[VCC_EN2],
                     vic->s32Pin[VCC_EN2][3]);
             pinctrl_gpio_set_pud_mode(vic->stPinCtrl, vic->u32Cam_en2[VCC_EN2],
                     vic->s32Pin[VCC_EN2][4]);
             pinctrl_gpio_set_pud_res(vic->stPinCtrl, vic->u32Cam_en2[VCC_EN2],
                     vic->s32Pin[VCC_EN2][5]);
             pinctrl_gpio_set_value(vic->stPinCtrl, vic->u32Cam_en2[VCC_EN2],
                     vic->s32Pin[VCC_EN2][6]);
        }

    }

    return 0;
}

static int viss_wb_dma_init(void)
{
    int ret = 0;
    const EI_CHAR *status;
    ret = config_get_string(VISS_WB_DMA_NAME, "status", &status);
    if (-1 == ret) {
        os_printk("ei wb_dma module Get status fail.\n");
    } else {
        g_stVissSrc.pvWbDmaBase = (EI_VOID *)(EI_UL)(VBASE_WB_DMA);
        ret = os_request_irq(INT_WB_DMA, VISS_WB_DMA_IrqHandler,
                    0, VISS_WB_DMA_NAME, &g_stVissSrc.pvWbDmaBase);
        if (ret) {
            os_printk("req irq err\n");
            return -1;
        }

    }
    os_printk("wb dma init end!\n");
    return 0;
}

static int ei_viss_wb_dma_exit(void)
{
    os_free_irq(INT_WB_DMA, &g_stVissSrc.pvWbDmaBase);
    return 0;
}

static int viss_mipi_init(const EI_CHAR *module)
{
    int ret = 0;
    const EI_CHAR *status;
    const EI_CHAR *mod_name;
    VISS_DEV Dev;
    EI_S32 i2c_num = -1;
    EI_S32 i2c_addr = -1;
    EI_U32 u32SnsMirror = 0;
    EI_U32 u32SnsFlip = 0;

    if (0 == strcmp(module, VISS_MIPI0_NAME)) {
        mod_name = VISS_MIPI0_NAME;
        Dev = 1;
    } else {
        mod_name = VISS_MIPI1_NAME;
        Dev = 2;
    }
    ret = config_get_string(mod_name, "status", &status);
    if (-1 == ret) {
        os_printk("ei mipi module Get status fail.\n");
    } else {
        if (0 == strcmp(status, "okay")) {
            if (0 == strcmp(module, VISS_MIPI0_NAME)) {
                g_stVissSrc.as32MdId[Dev] = VISS_MIPI0_MODULE_ID;
                g_stVissSrc.apvDevBases[Dev] = (EI_VOID *)(EI_UL)(VBASE_MIPI0);
                viss_pin_dev[Dev].u32Irqno = INT_MIPI_CSI0;
            } else {
                g_stVissSrc.as32MdId[Dev] = VISS_MIPI1_MODULE_ID;
                g_stVissSrc.apvDevBases[Dev] = (EI_VOID *)(EI_UL)(VBASE_MIPI2);
                viss_pin_dev[Dev].u32Irqno = INT_MIPI_CSI1;
            }
            g_stVissSrc.au32Freq[Dev] = MCSI_FREQ;
            g_stVissSrc.aenDevType[Dev] = MCSI;
            g_stVissSrc.au32Mclk[Dev] = 0;
            g_stVissSrc.u32DevId[Dev] = Dev;

            ret = os_request_irq(viss_pin_dev[Dev].u32Irqno, VISS_MCSI_IrqHandler,
                0, mod_name, &g_stVissSrc.u32DevId[Dev]);
            if (ret) {
                os_printk("req irq err\n");
                return -1;
            }

	    viss_pin_dev[Dev].u32DevId = g_stVissSrc.u32DevId[Dev];
            viss_pin_dev[Dev].stPinCtrl = pinctrl_get(mod_name);
            if (EI_NULL == viss_pin_dev[Dev].stPinCtrl)
                return EI_FAILURE;
            if (0 == strcmp(module, VISS_MIPI0_NAME))
                ret = pinctrl_enable_group(viss_pin_dev[Dev].stPinCtrl, MIPI0_GPIO_GROUP);
            else
                ret = pinctrl_enable_group(viss_pin_dev[Dev].stPinCtrl, MIPI1_GPIO_GROUP);
            if (ret) {
                pinctrl_put(viss_pin_dev[Dev].stPinCtrl);
                viss_pin_dev[Dev].stPinCtrl = EI_NULL;
                return EI_FAILURE;
            }

            ret = config_get_u32(mod_name, "i2c-bus", &i2c_num);
            if (-1 == ret)
                os_printk("no i2c_id for mcsi%d\n", Dev);
	    else
		viss_pin_dev[Dev].s32I2cBus = i2c_num;
	    g_stVissSrc.as32I2cBus[Dev] = i2c_num;

        ret = config_get_u32(mod_name, "i2c-addr", &i2c_addr);
        if (-1 == ret)
            os_printk("no i2c_addr for mcsi%d\n", Dev);
        else
            viss_pin_dev[Dev].s32I2cAddr = i2c_addr;

        g_stVissSrc.as32I2cAddr[Dev] = i2c_addr;

            ret = config_get_u32(mod_name, "sensor_flip", &u32SnsFlip);
            if (-1 == ret)
                os_printk("no Flip mcsi%d\n", Dev);
        else
                viss_pin_dev[Dev].u32SnsFlip = u32SnsFlip;
        g_stVissSrc.au32SnsFlip[Dev] = u32SnsFlip;

            ret = config_get_u32(mod_name, "sensor_mirror", &u32SnsMirror);
            if (-1 == ret)
                os_printk("no Mirror for mcsi%d\n", Dev);
            else
                viss_pin_dev[Dev].u32SnsMirror = u32SnsMirror;

            g_stVissSrc.au32SnsMirror[Dev] = u32SnsMirror;

            ei_viss_mcsi_reques_pins(&viss_pin_dev[Dev], module);
            ei_viss_ir_reques_pins(&viss_pin_dev[Dev], module);
            ei_viss_ms_reques_pins(&viss_pin_dev[Dev], module);
            g_stVissSrc.u32DevCount++;


        }

    }
    os_printk("VISS-MIPI-CSI registered successfully\n");
    return ret;

}
static int viss_vic_init(void)
{
    int ret = 0;
    const EI_CHAR *status;
    EI_S32 i2c_num = -1;
    EI_S32 i2c_addr = -1;
    EI_U32 u32SnsMirror = 0;
    EI_U32 u32SnsFlip = 0;

    ret = config_get_string(VISS_VIC_NAME, "status", &status);
    if (-1 == ret) {
       os_printk("ei viss module Get status fail.\n");
    } else {
        if (0 == strcmp(status, "okay")) {
        g_stVissSrc.as32MdId[g_stVissSrc.u32DevCount] = VISS_VIC_MODULE_ID;
        g_stVissSrc.au32Freq[g_stVissSrc.u32DevCount] = VIC_FREQ;
        g_stVissSrc.apvDevBases[g_stVissSrc.u32DevCount] = (EI_VOID *)(EI_UL)(VBASE_VIC);
        g_stVissSrc.aenDevType[g_stVissSrc.u32DevCount] = DVP;
        g_stVissSrc.au32Mclk[g_stVissSrc.u32DevCount] = 0;
        g_stVissSrc.u32DevId[g_stVissSrc.u32DevCount] = g_stVissSrc.u32DevCount;
        viss_pin_dev[g_stVissSrc.u32DevCount].u32Irqno = INT_VIC;

        ret = os_request_irq(viss_pin_dev[g_stVissSrc.u32DevCount].u32Irqno,
        VISS_VIC_IrqHandler, 0, VISS_VIC_NAME, &g_stVissSrc.u32DevId[g_stVissSrc.u32DevCount]);
        if (ret) {
            os_printk("req irq err\n");
            return -1;
        }

        viss_pin_dev[g_stVissSrc.u32DevCount].u32DevId = g_stVissSrc.u32DevId[g_stVissSrc.u32DevCount];
        viss_pin_dev[g_stVissSrc.u32DevCount].stPinCtrl = pinctrl_get(VISS_VIC_NAME);
	if (EI_NULL == viss_pin_dev[g_stVissSrc.u32DevCount].stPinCtrl)
		return EI_FAILURE;
	ret = pinctrl_enable_group(viss_pin_dev[g_stVissSrc.u32DevCount].stPinCtrl, VIC_GPIO_GROUP);
	if (ret) {
		pinctrl_put(viss_pin_dev[g_stVissSrc.u32DevCount].stPinCtrl);
		viss_pin_dev[g_stVissSrc.u32DevCount].stPinCtrl = EI_NULL;
		return EI_FAILURE;
	}
	ret = config_get_u32(VISS_VIC_NAME, "i2c-bus", &i2c_num);
	if (-1 == ret)
		os_printk("no i2c_id for vic\n");
	else
		viss_pin_dev[g_stVissSrc.u32DevCount].s32I2cBus = i2c_num;
	g_stVissSrc.as32I2cBus[g_stVissSrc.u32DevCount] = i2c_num;

    ret = config_get_u32(VISS_VIC_NAME, "i2c-addr", &i2c_addr);
    if (-1 == ret)
        os_printk("no i2c_addr for vic\n");
    else
        viss_pin_dev[g_stVissSrc.u32DevCount].s32I2cAddr = i2c_addr;

    g_stVissSrc.as32I2cAddr[g_stVissSrc.u32DevCount] = i2c_addr;

    ret = config_get_u32(VISS_VIC_NAME, "sensor_mirror", &u32SnsMirror);
    if (-1 == ret)
        os_printk("no Mirror for vic\n");
    else
        viss_pin_dev[g_stVissSrc.u32DevCount].u32SnsMirror = u32SnsMirror;
    g_stVissSrc.au32SnsMirror[g_stVissSrc.u32DevCount] = u32SnsMirror;

        ret = config_get_u32(VISS_VIC_NAME, "sensor_flip", &u32SnsFlip);
        if (-1 == ret)
            os_printk("no Flip for vic\n");
        else
            viss_pin_dev[g_stVissSrc.u32DevCount].u32SnsFlip = u32SnsFlip;

        g_stVissSrc.au32SnsFlip[g_stVissSrc.u32DevCount] = u32SnsFlip;

        ei_viss_vic_reques_pins(&viss_pin_dev[g_stVissSrc.u32DevCount], VISS_VIC_NAME);
        ei_viss_ir_reques_pins(&viss_pin_dev[g_stVissSrc.u32DevCount], VISS_VIC_NAME);
        ei_viss_ms_reques_pins(&viss_pin_dev[g_stVissSrc.u32DevCount], VISS_VIC_NAME);
        g_stVissSrc.u32DevCount++;

        }
    }
    os_printk("VISS-VIC registered successfully\n");
    return ret;
}
int ei_viss_dev_exit(VISS_DEV_S *pdev)
{
    EI_U32 i;


    for (i = 0; i < SNS_DELAY; i++) {

        if (pdev->u32Rst[i] >= 0)
	   pinctrl_gpio_free(pdev->stPinCtrl, pdev->u32Rst[i]);
	if (pdev->u32Pwdn[i] >= 0)
	   pinctrl_gpio_free(pdev->stPinCtrl, pdev->u32Pwdn[i]);
	if (pdev->u32Mclk[i] >= 0)
	   pinctrl_gpio_free(pdev->stPinCtrl, pdev->u32Mclk[i]);
	if (pdev->u32Cam_en0[i] >= 0)
	   pinctrl_gpio_free(pdev->stPinCtrl, pdev->u32Cam_en0[i]);
	if (pdev->u32Cam_en1[i] >= 0)
	   pinctrl_gpio_free(pdev->stPinCtrl, pdev->u32Cam_en1[i]);
	if (pdev->u32Cam_en2[i] >= 0)
	   pinctrl_gpio_free(pdev->stPinCtrl, pdev->u32Cam_en2[i]);

    }
    pinctrl_put(pdev->stPinCtrl);
    pdev->stPinCtrl = EI_NULL;
    os_free_irq(pdev->u32Irqno, &pdev->u32DevId);

    os_printk("------------------\n");
    os_printk("-----ei_viss_dev%d_exit---\n", pdev->u32DevId);
    os_printk("------------------\n");

    return 0;
}
int viss_driver_init(void)
{
    int i = 0;
    /* char *module = VISS_MODULE_NAME; */
    os_printk("------------------\n");
    os_printk("-----viss_driver_init---\n");
    os_printk("------------------\n");

    os_printk("viss_driver_init begin\n");
    for (i = 0; i < VISS_MAX_DEV_NUM; i++) {
        g_stVissSrc.as32MdId[i] = -1;
        g_stVissSrc.as32I2cBus[i] = -1;
        g_stVissSrc.as32I2cAddr[i] = -1;
        g_stVissSrc.au32SnsMirror[i] = -1;
        g_stVissSrc.au32SnsFlip[i] = -1;
#if defined ARCH_LOMBO_N7V7
        g_stVissSrc.useHfclkFlag[VISS_MAX_DEV_NUM] = EI_FALSE;
#endif
    }
    g_stVissSrc.pvTopBase = (EI_VOID *)(EI_UL)(VBASE_VISS);

    /* os_platform_clk_prepare_enable_all(module); */
    viss_md_top_clk_init();
    viss_vic_init();
    viss_mipi_init(VISS_MIPI0_NAME);
    viss_mipi_init(VISS_MIPI1_NAME);
    viss_wb_dma_init();


    VISS_ModInit();

    os_printk("viss_driver_init end\n");
    return 0;
}

int viss_driver_exit(void)
{
    int i = 0;
    /* char *module = VISS_MODULE_NAME; */
    os_printk("------------------\n");
    os_printk("-----ei_viss_driver_exit---\n");
    os_printk("------------------\n");

     ei_viss_wb_dma_exit();
     for (i = 0; i < VISS_MAX_DEV_NUM; i++) {
     	if (viss_pin_dev[i].stPinCtrl)
           ei_viss_dev_exit(&viss_pin_dev[i]);
    }

     /* os_platform_clk_disable_unprepare_all(module); */
     viss_md_top_clk_exit();
     return 0;
}

#else
#define viss_check_pointer(ptr)\
    do {\
        if (NULL == ptr)\
        {\
            os_printk("Null Pointer!\n");\
            return -ENOENT;\
        }\
    }while(0)

#define VISS_OF_NODE_NAME           "ei_viss"
#define VISS_VIC_OF_NODE_NAME       "ei_vic"
#define VISS_MCSI_OF_NODE_NAME      "ei_mipi"
#define VISS_WB_DMA_OF_NODE_NAME    "ei_wb_dma"

typedef struct eiVISS_PINCTRL_S {
    struct pinctrl              *stPinCtrl;
    struct pinctrl_state        *stStateDefault;
    struct pinctrl_state        *stStateIdle;
} VISS_PINCTRL_S;

typedef struct eiVISS_WB_DMA_S {
    struct platform_device      *pdev;
    void __iomem                *regs;
    struct resource             *res;
} VISS_WB_DMA_S;

typedef struct eiVISS_DEV_S {
    struct platform_device      *pdev;

    struct clk                  *clock;
    void __iomem                *regs;
    struct resource             *res;

    EI_U32                      u32Freq;
    EI_S32                      s32MdId;
    EI_S32                      s32I2cBus;
    EI_S32                      s32I2cAddr;
    EI_U32                      u32DevId;
    VISS_PINCTRL_S              stPinCtrl;
    EI_S32                      s32Pin[SNS_PWR_ACT_MAX];
    VISS_DEV_TYPE_E             enDevType;
    EI_U32                      u32mclk;
    VISS_AUDIO_ATTR_S           stAudioAttr;
    EI_U32                     u32SnsMirror;
    EI_U32                     u32SnsFlip;
#if defined ARCH_LOMBO_N7V7
    EI_BOOL                    useHfclkFlag;
#endif
} VISS_DEV_S;

typedef struct eiVISS_TOP_S {
    struct platform_device  *pdev;
    struct clk              *srcclk0;
    struct clk              *srcclk1;
    struct clk              *viss_reset;
    struct clk              *viss_gate;
    struct clk              *viss_axi_gate;
    void __iomem            *regs;
    EI_U32                  u32DevCount;
    VISS_DEV_S              stDev[VISS_MAX_DEV_NUM];
    VISS_WB_DMA_S           stWbDma;
} VISS_TOP_S;

static VISS_TOP_S *g_pstVissTop;

int VISS_DEV_SetPinState(VISS_DEV dev,  CAMERA_POWER_ACT_S *pAct)
{
    VISS_DEV_S *csi = &g_pstVissTop->stDev[dev];

    if (pAct->u8Act >= SNS_PWR_ACT_MAX) {
        PRT_VISS_ERR("pAct->u8Act err\n");
        return EI_FAILURE;
    }

    if (csi->s32Pin[pAct->u8Act] == -1) {
        switch (pAct->u8Act) {
            case SNS_RESET:
                PRT_VISS_ERR("SNS_RESET\n");
                break;
            case SNS_PWDN:
                PRT_VISS_ERR("SNS_PWDN\n");
                break;
            case SNS_IR_RESET:
                PRT_VISS_ERR("SNS_IR_RESET\n");
                break;
            case SNS_IR_PWDN:
                PRT_VISS_ERR("SNS_IR_PWDN\n");
                break;
            case MS_RESET:
                PRT_VISS_ERR("MS_RESET\n");
                break;
            case MS_VD_FZ:
                PRT_VISS_ERR("MS_VD_FZ\n");
                break;
            case CAM_EN:
            case CAM_EN0:
            case CAM_EN1:
            case CAM_EN2:
                break;
                PRT_VISS_ERR("CAM_EN\n");
                break;
            case MS_INXA1:
                PRT_VISS_ERR("MS_INXA1\n");
                break;
            case MS_INXA2:
                PRT_VISS_ERR("MS_INXA2\n");
                break;
            case MS_INXB1:
                PRT_VISS_ERR("MS_INXB1\n");
                break;
            case MS_INXB2:
                PRT_VISS_ERR("MS_INXB2\n");
                break;
            case MS_INXC1:
                PRT_VISS_ERR("MS_INXC1\n");
                break;
            case MS_INXC2:
                PRT_VISS_ERR("MS_INXC2\n");
                break;
            case MS_INXD1:
                PRT_VISS_ERR("MS_INXD1\n");
                break;
            case MS_INXD2:
                PRT_VISS_ERR("MS_INXD2\n");
                break;
            default:
                PRT_VISS_ERR("pAct->u8Act err\n");
                break;
        }
        return EI_SUCCESS;
    }

    if (csi->s32Pin[pAct->u8Act] >= 0xADC0) {
        lombo_write_ainx_output(csi->s32Pin[pAct->u8Act] - 0xADC0, pAct->u8Ud);
    } else {
        gpio_direction_output(csi->s32Pin[pAct->u8Act], pAct->u8Ud);
    }

    return EI_SUCCESS;
}

static inline int VISS_DEV_GetPinctrl(VISS_DEV_S *mcsi)
{
    struct device *dev = &mcsi->pdev->dev;
    VISS_PINCTRL_S *pstPctl = &mcsi->stPinCtrl;

    pstPctl->stPinCtrl = devm_pinctrl_get(dev);
    if (pstPctl->stPinCtrl == EI_NULL) {
        return EI_FAILURE;
    }

    pstPctl->stStateDefault = pinctrl_lookup_state(pstPctl->stPinCtrl,
            PINCTRL_STATE_DEFAULT);
    if (pstPctl->stStateDefault == EI_NULL) {
        return EI_FAILURE;
    }

    pstPctl->stStateIdle = pinctrl_lookup_state(pstPctl->stPinCtrl,
            PINCTRL_STATE_IDLE);
    pinctrl_select_state(pstPctl->stPinCtrl, pstPctl->stStateDefault);

    return 0;
}

static int ei_viss_mcsi_request_pins(VISS_DEV_S *mcsi, struct device_node *np)
{
    enum of_gpio_flags flags;
    EI_S32 s32PwdnPinAdcNum = 0xff;
    EI_S32 s32ResetPinAdcNum = 0xff;
    int ret = 0;

    mcsi->s32Pin[SNS_RESET] = of_get_named_gpio_flags(np,
            "mcsi_reset_pin", 0, &flags);
    mcsi->s32Pin[SNS_PWDN] = of_get_named_gpio_flags(np,
            "mcsi_pwdn_pin", 0, &flags);
#if defined ARCH_LOMBO_N7V7
        mcsi->s32Pin[SNS_MCLK] = of_get_named_gpio_flags(np,
            "mcsi_mclk_pin", 0, &flags);
        if (!gpio_is_valid(mcsi->s32Pin[SNS_MCLK]))
	   mcsi->useHfclkFlag = EI_FALSE;
	else
	   mcsi->useHfclkFlag = EI_TRUE;
#endif

    if (!gpio_is_valid(mcsi->s32Pin[SNS_RESET])) {
        PRT_VISS_WARN("no reset pin for %s (%d)\n", dev_name(&mcsi->pdev->dev),
            mcsi->s32Pin[SNS_RESET]);
        of_property_read_u32(np, "mcsi_reset_pin_gpadc", &s32ResetPinAdcNum);
        if (s32ResetPinAdcNum < 0) {
            PRT_VISS_WARN("ei viss %s mcsi_reset_pin_gpadc fail, pin:%d\n",
                dev_name(&mcsi->pdev->dev), s32ResetPinAdcNum);
            mcsi->s32Pin[SNS_RESET] = -1;
        } else {
            mcsi->s32Pin[SNS_RESET] = 0xADC0 + s32ResetPinAdcNum;
            lombo_write_ainx_output(s32ResetPinAdcNum, 0);
        }
    } else {
        ret = devm_gpio_request(&mcsi->pdev->dev, mcsi->s32Pin[SNS_RESET],
                "mcsi_reset_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s reset_pin)\n",
                mcsi->s32Pin[SNS_RESET],dev_name(&mcsi->pdev->dev));
            mcsi->s32Pin[SNS_RESET] = -1;
            mcsi->s32Pin[SNS_PWDN] = -1;
            return -EBUSY;
        }
#ifndef CONFIG_LOMBO_DOUBLE_OS
        gpio_direction_output(mcsi->s32Pin[SNS_RESET], 0);
#endif
    }

    if (!gpio_is_valid(mcsi->s32Pin[SNS_PWDN])) {
        PRT_VISS_WARN("no pwdn pin for %s (%d)\n", dev_name(&mcsi->pdev->dev),
            mcsi->s32Pin[SNS_PWDN]);
        of_property_read_u32(np, "mcsi_pwdn_pin_gpadc", &s32PwdnPinAdcNum);
        if (s32PwdnPinAdcNum < 0) {
            PRT_VISS_WARN("ei viss %s mcsi_pwdn_pin_gpadc fail, pin:%d\n",
                dev_name(&mcsi->pdev->dev), s32PwdnPinAdcNum);
            mcsi->s32Pin[SNS_PWDN] = -1;
        } else {
            mcsi->s32Pin[SNS_PWDN] = 0xADC0 + s32PwdnPinAdcNum;
            lombo_write_ainx_output(s32PwdnPinAdcNum, 0);
        }
    } else {
        ret = devm_gpio_request(&mcsi->pdev->dev, mcsi->s32Pin[SNS_PWDN],
                "mcsi_pwdn_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s pwdn_pin)\n",
                mcsi->s32Pin[SNS_PWDN], dev_name(&mcsi->pdev->dev));
            mcsi->s32Pin[SNS_RESET] = -1;
            mcsi->s32Pin[SNS_PWDN] = -1;
            return -EBUSY;
        }
#ifndef CONFIG_LOMBO_DOUBLE_OS
        gpio_direction_output(mcsi->s32Pin[SNS_PWDN], 0);
#endif
    }

    return 0;
}

static int ei_viss_vic_request_pins(VISS_DEV_S *vic, struct device_node *np)
{
    enum of_gpio_flags flags;
    EI_S32 s32PwdnPinAdcNum = 0xff;
    EI_S32 s32ResetPinAdcNum = 0xff;
    int ret = 0;

    vic->s32Pin[SNS_RESET] = of_get_named_gpio_flags(np,
            "dvp_reset_pin", 0, &flags);
    vic->s32Pin[SNS_PWDN] = of_get_named_gpio_flags(np,
            "dvp_pwdn_pin", 0, &flags);
#if defined ARCH_LOMBO_N7V7
        vic->s32Pin[SNS_MCLK] = of_get_named_gpio_flags(np,
            "dvp_mclk_pin", 0, &flags);
        if (!gpio_is_valid(vic->s32Pin[SNS_MCLK]))
	   vic->useHfclkFlag = EI_FALSE;
	else
	   vic->useHfclkFlag = EI_TRUE;
#endif

    if (!gpio_is_valid(vic->s32Pin[SNS_RESET])) {
        PRT_VISS_WARN("no reset pin for %s (%d)\n", dev_name(&vic->pdev->dev),
            vic->s32Pin[SNS_RESET]);
        of_property_read_u32(np, "dvp_reset_pin_gpadc", &s32ResetPinAdcNum);
        if (s32ResetPinAdcNum < 0) {
            PRT_VISS_WARN("ei viss %s dvp_reset_pin_gpadc fail, pin:%d\n",
                dev_name(&vic->pdev->dev), s32ResetPinAdcNum);
            vic->s32Pin[SNS_RESET] = -1;
        } else {
            vic->s32Pin[SNS_RESET] = 0xADC0 + s32ResetPinAdcNum;
            lombo_write_ainx_output(s32ResetPinAdcNum, 0);
        }
    } else {
        ret = devm_gpio_request(&vic->pdev->dev, vic->s32Pin[SNS_RESET],
                "dvp_reset_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s reset_pin)\n",
                vic->s32Pin[SNS_RESET], dev_name(&vic->pdev->dev));
            vic->s32Pin[SNS_RESET] = -1;
            vic->s32Pin[SNS_PWDN] = -1;
            return -EBUSY;
        }
#ifndef CONFIG_LOMBO_DOUBLE_OS
        gpio_direction_output(vic->s32Pin[SNS_RESET], 0);
#endif
    }

    if (!gpio_is_valid(vic->s32Pin[SNS_PWDN])) {
        PRT_VISS_WARN("no pwdn pin for %s (%d)\n", dev_name(&vic->pdev->dev),
            vic->s32Pin[SNS_PWDN]);
        of_property_read_u32(np, "dvp_pwdn_pin_gpadc", &s32PwdnPinAdcNum);
        if (s32PwdnPinAdcNum < 0) {
            PRT_VISS_WARN("ei viss %s dvp_pwdn_pin_gpadc fail, pin:%d\n",
                dev_name(&vic->pdev->dev), s32PwdnPinAdcNum);
            vic->s32Pin[SNS_PWDN] = -1;
        } else {
            vic->s32Pin[SNS_PWDN] = 0xADC0 + s32PwdnPinAdcNum;
            lombo_write_ainx_output(s32PwdnPinAdcNum, 0);
        }
    } else {
        ret = devm_gpio_request(&vic->pdev->dev, vic->s32Pin[SNS_PWDN],
                "dvp_pwdn_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s pwdn_pin)\n",
                vic->s32Pin[SNS_PWDN], dev_name(&vic->pdev->dev));
            vic->s32Pin[SNS_RESET] = -1;
            vic->s32Pin[SNS_PWDN] = -1;
            return -EBUSY;
        }
#ifndef CONFIG_LOMBO_DOUBLE_OS
        gpio_direction_output(vic->s32Pin[SNS_PWDN], 0);
#endif
    }

    return 0;
}

static int ei_viss_ir_request_pins(VISS_DEV_S *vic, struct device_node *np)
{
    enum of_gpio_flags flags;
    int ret = 0;

    vic->s32Pin[SNS_IR_RESET] = of_get_named_gpio_flags(np,
            "ir_reset_pin", 0, &flags);
    vic->s32Pin[SNS_IR_PWDN] = of_get_named_gpio_flags(np,
            "ir_pwdn_pin", 0, &flags);

    if (!gpio_is_valid(vic->s32Pin[SNS_IR_RESET])) {
        PRT_VISS_WARN("no ir reset pin for %s (%d)\n", dev_name(&vic->pdev->dev),
            vic->s32Pin[SNS_IR_RESET]);
        vic->s32Pin[SNS_IR_RESET] = -1;
    } else {
        ret = devm_gpio_request(&vic->pdev->dev, vic->s32Pin[SNS_IR_RESET],
                "ir_reset_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s ir_reset_pin)\n",
                vic->s32Pin[SNS_IR_RESET], dev_name(&vic->pdev->dev));
            vic->s32Pin[SNS_IR_RESET] = -1;
            vic->s32Pin[SNS_IR_PWDN] = -1;
            return -EBUSY;
        }
#ifndef CONFIG_LOMBO_DOUBLE_OS
        gpio_direction_output(vic->s32Pin[SNS_IR_RESET], 0);
#endif
    }

    if (!gpio_is_valid(vic->s32Pin[SNS_IR_PWDN])) {
        PRT_VISS_WARN("no ir pwdn pin for %s (%d)\n", dev_name(&vic->pdev->dev),
            vic->s32Pin[SNS_IR_PWDN]);
        vic->s32Pin[SNS_IR_PWDN] = -1;
    } else {
        ret = devm_gpio_request(&vic->pdev->dev, vic->s32Pin[SNS_IR_PWDN],
                "ir_pwdn_pin");
        if (ret < 0) {
            PRT_VISS_ERR("pin %d request failed (%s ir_pwdn_pin)\n",
                vic->s32Pin[SNS_IR_PWDN], dev_name(&vic->pdev->dev));
            vic->s32Pin[SNS_IR_RESET] = -1;
            vic->s32Pin[SNS_IR_PWDN] = -1;
            return -EBUSY;
        }
#ifndef CONFIG_LOMBO_DOUBLE_OS
        gpio_direction_output(vic->s32Pin[SNS_IR_PWDN], 0);
#endif
    }

    return 0;
}

static int ei_viss_ms_request_pins(VISS_DEV_S *vic, struct device_node *np)
{
    enum of_gpio_flags flags;
    int ret = 0;
    EI_S8 *ps8MsInfoStr[] = {
        "ms_inxa1_pin",
        "ms_inxa2_pin",
        "ms_inxb1_pin",
        "ms_inxb2_pin",
        "ms_inxc1_pin",
        "ms_inxc2_pin",
        "ms_inxd1_pin",
        "ms_inxd2_pin",
    };
    EI_U32 u32Index = 0;

    vic->s32Pin[MS_RESET] = of_get_named_gpio_flags(np,
            "ms_reset_pin", 0, &flags);
    vic->s32Pin[MS_VD_FZ] = of_get_named_gpio_flags(np,
            "ms_vd_fz_pin", 0, &flags);

    if (!gpio_is_valid(vic->s32Pin[MS_RESET])) {
        PRT_VISS_WARN("no ms reset pin for %s (%d)\n", dev_name(&vic->pdev->dev),
            vic->s32Pin[MS_RESET]);
        vic->s32Pin[MS_RESET] = -1;
    } else {
        ret = devm_gpio_request(&vic->pdev->dev, vic->s32Pin[MS_RESET],
                "ms_reset_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s ms_reset_pin)\n",
                vic->s32Pin[MS_RESET], dev_name(&vic->pdev->dev));
            vic->s32Pin[MS_RESET] = -1;
            vic->s32Pin[MS_VD_FZ] = -1;
            return -EBUSY;
        }
#ifndef CONFIG_LOMBO_DOUBLE_OS
        gpio_direction_output(vic->s32Pin[MS_RESET], 0);
#endif
    }

    if (!gpio_is_valid(vic->s32Pin[MS_VD_FZ])) {
        PRT_VISS_WARN("no ms_vd_fz_pin for %s (%d)\n", dev_name(&vic->pdev->dev),
            vic->s32Pin[MS_VD_FZ]);
        vic->s32Pin[MS_VD_FZ] = -1;
    } else {
        ret = devm_gpio_request(&vic->pdev->dev, vic->s32Pin[MS_VD_FZ],
                "ms_vd_fz_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s ms_vd_fz_pin)\n",
                vic->s32Pin[MS_VD_FZ], dev_name(&vic->pdev->dev));
            vic->s32Pin[MS_RESET] = -1;
            vic->s32Pin[MS_VD_FZ] = -1;
            return -EBUSY;
        }
#ifndef CONFIG_LOMBO_DOUBLE_OS
        gpio_direction_output(vic->s32Pin[MS_VD_FZ], 0);
#endif
    }

    for (u32Index = MS_INXA1; u32Index <= MS_INXD2; u32Index++) {
        vic->s32Pin[u32Index] = of_get_named_gpio_flags(np,
            ps8MsInfoStr[u32Index - MS_INXA1], 0, &flags);
        if (!gpio_is_valid(vic->s32Pin[u32Index])) {
            PRT_VISS_WARN("no %s for %s (%d)\n",
                ps8MsInfoStr[u32Index - MS_INXA1], dev_name(&vic->pdev->dev), vic->s32Pin[u32Index]);
            vic->s32Pin[u32Index] = -1;
            return ret;
        } else {
            ret = devm_gpio_request(&vic->pdev->dev, vic->s32Pin[u32Index],
                    ps8MsInfoStr[u32Index - MS_INXA1]);
            if (ret < 0) {
                PRT_VISS_ERR("pin %d request failed (%s %s)\n",
                    vic->s32Pin[u32Index], dev_name(&vic->pdev->dev), ps8MsInfoStr[u32Index - MS_INXA1]);
                vic->s32Pin[u32Index] = -1;
                return -EBUSY;
            }
#ifndef CONFIG_LOMBO_DOUBLE_OS
            gpio_direction_output(vic->s32Pin[u32Index], 0);
#endif
        }
    }

    return 0;
}

static int ei_viss_cam_en_request_pins(VISS_DEV_S *dev, struct device_node *np)
{
    enum of_gpio_flags flags;
    int ret = 0;

    dev->s32Pin[CAM_EN] = of_get_named_gpio_flags(np,
            "cam_en_pin", 0, &flags);

    if (!gpio_is_valid(dev->s32Pin[CAM_EN])) {
        PRT_VISS_WARN("no cam en pin for %s (%d)\n", dev_name(&dev->pdev->dev),
            dev->s32Pin[CAM_EN]);
        dev->s32Pin[CAM_EN] = -1;
    } else {
        ret = devm_gpio_request(&dev->pdev->dev, dev->s32Pin[CAM_EN],
                "cam_en_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s cam_en_pin)\n",
                dev->s32Pin[CAM_EN], dev_name(&dev->pdev->dev));
            dev->s32Pin[CAM_EN] = -1;
            return -EBUSY;
        }
#ifndef CONFIG_LOMBO_DOUBLE_OS
        gpio_direction_output(dev->s32Pin[CAM_EN], 0);
#endif
    }


    dev->s32Pin[CAM_EN0] = of_get_named_gpio_flags(np,
            "cam_en0_pin", 0, &flags);

    if (!gpio_is_valid(dev->s32Pin[CAM_EN0])) {
        PRT_VISS_WARN("no cam en0 pin for %s (%d)\n", dev_name(&dev->pdev->dev),
            dev->s32Pin[CAM_EN0]);
        dev->s32Pin[CAM_EN0] = -1;
    } else {
        ret = devm_gpio_request(&dev->pdev->dev, dev->s32Pin[CAM_EN0],
                "cam_en0_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s cam_en0_pin)\n",
                dev->s32Pin[CAM_EN0], dev_name(&dev->pdev->dev));
            dev->s32Pin[CAM_EN0] = -1;
            return -EBUSY;
        }
        gpio_direction_output(dev->s32Pin[CAM_EN0], 0);
    }

    dev->s32Pin[CAM_EN1] = of_get_named_gpio_flags(np,
            "cam_en1_pin", 0, &flags);

    if (!gpio_is_valid(dev->s32Pin[CAM_EN1])) {
        PRT_VISS_WARN("no cam en1 pin for %s (%d)\n", dev_name(&dev->pdev->dev),
            dev->s32Pin[CAM_EN1]);
        dev->s32Pin[CAM_EN1] = -1;
    } else {
        ret = devm_gpio_request(&dev->pdev->dev, dev->s32Pin[CAM_EN1],
                "cam_en1_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s cam_en1_pin)\n",
                dev->s32Pin[CAM_EN1], dev_name(&dev->pdev->dev));
            dev->s32Pin[CAM_EN1] = -1;
            return -EBUSY;
        }
        gpio_direction_output(dev->s32Pin[CAM_EN1], 0);
    }

    dev->s32Pin[CAM_EN2] = of_get_named_gpio_flags(np,
            "cam_en2_pin", 0, &flags);

    if (!gpio_is_valid(dev->s32Pin[CAM_EN2])) {
        PRT_VISS_WARN("no cam en2 pin for %s (%d)\n", dev_name(&dev->pdev->dev),
            dev->s32Pin[CAM_EN2]);
        dev->s32Pin[CAM_EN2] = -1;
    } else {
        ret = devm_gpio_request(&dev->pdev->dev, dev->s32Pin[CAM_EN2],
                "cam_en2_pin");
        if (ret < 0) {
            PRT_VISS_WARN("pin %d request failed (%s cam_en2_pin)\n",
                dev->s32Pin[CAM_EN2], dev_name(&dev->pdev->dev));
            dev->s32Pin[CAM_EN2] = -1;
            return -EBUSY;
        }
        gpio_direction_output(dev->s32Pin[CAM_EN2], 0);
    }

    return 0;
}

int ei_viss_wb_dma_init(struct platform_device *pdev, VISS_WB_DMA_S *wb_dma)
{
    struct device *dev = &pdev->dev;
    int ret = 0;
    struct resource *res;
    struct device_node *np = pdev->dev.of_node;

    wb_dma->pdev = pdev;

    res = os_platform_get_resource(pdev, IORESOURCE_MEM, 0);
    viss_check_pointer(res);

    wb_dma->regs = of_iomap(np, 0);
    viss_check_pointer(wb_dma->regs);

    wb_dma->res = os_platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    viss_check_pointer(wb_dma->res);

    ret = os_request_irq(wb_dma->res->start, VISS_WB_DMA_IrqHandler,
                    0, dev_name(dev), wb_dma);
    if (ret) {
        os_printk("req irq err\n");
        return -1;
    }

    platform_set_drvdata(pdev, wb_dma);

    return 0;
}

int ei_viss_wb_dma_exit(struct platform_device *pdev)
{
    VISS_WB_DMA_S *wb_dma = platform_get_drvdata(pdev);

    os_free_irq(wb_dma->res->start, wb_dma);

    return 0;
}

int ei_viss_mcsi_init(struct platform_device *pdev, VISS_DEV_S *mcsi)
{
    struct device *dev = &pdev->dev;
    struct resource *res;
    int ret;
    struct device_node *np = NULL;
    EI_S32 fpga_flag = 0;

    np = pdev->dev.of_node;

    if (dev->of_node == NULL) {
        os_printk("no device data specified\n");
        return -ENOENT;
    }

#if defined CONFIG_ARCH_LOMBO_N7V7_FPGA
    os_printk("FPGA viss don't need pinctrl...\n");
    fpga_flag = 1;
#endif

    mcsi->pdev = pdev;

    res = os_platform_get_resource(pdev, IORESOURCE_MEM, 0);
    viss_check_pointer(res);

    mcsi->regs = of_iomap(np, 0);
    viss_check_pointer(mcsi->regs);

    mcsi->res = os_platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    viss_check_pointer(mcsi->res);

    ret = os_request_irq(mcsi->res->start, VISS_MCSI_IrqHandler,
            0, dev_name(dev), &mcsi->u32DevId);
    if (ret) {
        os_printk("req irq err\n");
        return -1;
    }

    if (!fpga_flag) {
        ret = VISS_DEV_GetPinctrl(mcsi);
        if (ret < 0) {
            os_printk("Failed to get mcsi pinctrl: %d", ret);
        }

        ei_viss_mcsi_request_pins(mcsi, pdev->dev.of_node);
        ei_viss_ir_request_pins(mcsi, pdev->dev.of_node);
        ei_viss_ms_request_pins(mcsi, pdev->dev.of_node);
        ei_viss_cam_en_request_pins(mcsi, pdev->dev.of_node);
    }

    platform_set_drvdata(pdev, mcsi);

    return 0;
}

int ei_viss_vic_init(struct platform_device *pdev, VISS_DEV_S *vic)
{
    struct device *dev = &pdev->dev;
    struct resource *res;
    int ret;
    struct device_node *np = pdev->dev.of_node;
    EI_S32 fpga_flag = 0;

    if (dev->of_node == NULL) {
        os_printk("no device data specified\n");
        return -ENOENT;
    }

#if defined CONFIG_ARCH_LOMBO_N7V7_FPGA
    os_printk("FPGA viss don't need pinctrl...\n");
    fpga_flag = 1;
#endif

    vic->pdev = pdev;

    res = os_platform_get_resource(pdev, IORESOURCE_MEM, 0);
    viss_check_pointer(res);

    vic->regs = of_iomap(np, 0);
    viss_check_pointer(vic->regs);

    vic->res = os_platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    viss_check_pointer(vic->res);

    ret = os_request_irq(vic->res->start, VISS_VIC_IrqHandler,
            0, dev_name(dev), &vic->u32DevId);
    if (ret) {
        os_printk("req irq err\n");
        return -1;
    }

    if (!fpga_flag) {
        ret = VISS_DEV_GetPinctrl(vic);
        if (ret < 0) {
            os_printk("Failed to get vic pinctrl: %d", ret);
        }

        ei_viss_vic_request_pins(vic, pdev->dev.of_node);
        ei_viss_ir_request_pins(vic, pdev->dev.of_node);
        ei_viss_ms_request_pins(vic, pdev->dev.of_node);
        ei_viss_cam_en_request_pins(vic, pdev->dev.of_node);
    }

    platform_set_drvdata(pdev, vic);

    return 0;
}

int ei_viss_dev_exit(struct platform_device *pdev)
{
    EI_U32 i;
    VISS_DEV_S *Dev = platform_get_drvdata(pdev);

    for (i = 0; i < VCC_EN0; i++) {
        if (gpio_is_valid(Dev->s32Pin[i])) {
            devm_gpio_free(&Dev->pdev->dev, Dev->s32Pin[i]);
        }
    }

    os_free_irq(Dev->res->start, &Dev->u32DevId);

    os_printk("-----ei_viss_dev%d_exit---\n", Dev->u32DevId);

    return 0;
}

#ifdef CONFIG_PM_GENERIC_DOMAINS
static struct clk *platform_clk_get(void *dev, int index)
{
	struct of_phandle_args clkspec;
	struct platform_device *pdev = (struct platform_device *)dev;
	struct device_node *node;
	struct clk *clk = NULL;
	int rc, num_clks;

	if (!pdev) {
		pr_err("invalid parameter!\n");
		goto err;
	}
	node = pdev->dev.of_node;

	num_clks = of_count_phandle_with_args(node, "assigned-clocks",
						 "#clock-cells");
	if (num_clks < 0) {
		pr_err("clk: invalid value of assigned-clocks property for %s\n",
		       pdev->name);
		goto err;
	}

	if (index >= num_clks) {
		pr_err("%s clk: index(%d) is out of range(%d)\n",
		       pdev->name, index, num_clks - 1);
		goto err;
	}

	rc = of_parse_phandle_with_args(node, "assigned-clocks",
				"#clock-cells", index, &clkspec);
	if (rc < 0)
		goto err;
	clk = of_clk_get_from_provider(&clkspec);
	if (IS_ERR_OR_NULL(clk)) {
		if (PTR_ERR(clk) != -EPROBE_DEFER)
			pr_warn("clk: couldn't get assigned clock %d for %s\n",
				index, node->name);
		goto err;
	}

err:
	return clk;
}
#endif

static int ei_viss_top_config_child(VISS_TOP_S *vmd, struct device_node *parent)
{
    struct device_node *node;
    int ret = 0;
    EI_S32 s32MdId = -1;
    VISS_DEV Dev = 0;
    EI_S32 s32I2cBus = -1;
    EI_S32 s32I2cAddr = -1;
    EI_U32 au32Audio[4] = {0};
    EI_U32 u32SnsMirror = 0;
    EI_U32 u32SnsFlip = 0;

    for_each_available_child_of_node(parent, node) {
        struct platform_device *pdev;
        EI_U32 mclk = 0;
        EI_U32 freq = 0;
        au32Audio[0] = 0;
        au32Audio[1] = 0;
        au32Audio[2] = 0;
        au32Audio[3] = 0;

        pdev = of_find_device_by_node(node);
        if (!pdev) {
            continue;
        }

        if (!strcmp(node->name, VISS_VIC_OF_NODE_NAME)) {
            ret = of_property_read_u32(node, "clock-frequency", &freq);
            if (freq < VIC_FREQ) {
                freq = VIC_FREQ;
                os_printk("vic set as minimum %d\n", VIC_FREQ);
            }

            ret = of_property_read_u32(node, "module-id", &s32MdId);
            if (s32MdId < 0) {
                os_printk("ei viss module id err:%d\n", s32MdId);
                continue;
            }

            Dev = s32MdId;

            of_property_read_u32(node, "i2c-bus", &s32I2cBus);
            if (s32I2cBus < 0) {
               PRT_VISS_WARN("ei viss %s i2c-bus id:%d\n", dev_name(&pdev->dev), s32I2cBus);
            }

            of_property_read_u32(node, "i2c-addr", &s32I2cAddr);
            if (s32I2cAddr < 0) {
               PRT_VISS_WARN("ei viss %s i2c-addr:0x%x\n", dev_name(&pdev->dev), s32I2cAddr);
            }

            if (!of_property_read_u32(node, "mclk", &mclk))
                vmd->stDev[Dev].u32mclk = mclk;
            else
                vmd->stDev[Dev].u32mclk = 0;

            if (!of_property_read_u32_array(node, "tp-audio", au32Audio, 4)) {
                vmd->stDev[Dev].stAudioAttr.u32SampleRate = au32Audio[0];
                vmd->stDev[Dev].stAudioAttr.u32BitWidth = au32Audio[1];
                vmd->stDev[Dev].stAudioAttr.u32ChnNum = au32Audio[2];
                vmd->stDev[Dev].stAudioAttr.u32Volume = au32Audio[3];
            }

            if (!of_property_read_u32(node, "sensor_mirror", &u32SnsMirror)) {
                vmd->stDev[Dev].u32SnsMirror = u32SnsMirror;
            }
            if (!of_property_read_u32(node, "sensor_flip", &u32SnsFlip)) {
                vmd->stDev[Dev].u32SnsFlip = u32SnsFlip;
            }

            vmd->stDev[Dev].enDevType = DVP;
            vmd->stDev[Dev].s32MdId = s32MdId;
            vmd->stDev[Dev].u32Freq = freq;
            vmd->stDev[Dev].u32DevId = Dev;
            vmd->stDev[Dev].s32I2cBus = s32I2cBus;
            vmd->stDev[Dev].s32I2cAddr = s32I2cAddr;

            ei_viss_vic_init(pdev, &vmd->stDev[Dev]);
            vmd->u32DevCount++;
        } else if (!strcmp(node->name, VISS_MCSI_OF_NODE_NAME)) {
            ret = of_property_read_u32(node, "clock-frequency", &freq);
            if (freq < MCSI_FREQ) {
                freq = MCSI_FREQ;
                os_printk("mcsi set as minimum %d\n", MCSI_FREQ);
            }

            ret = of_property_read_u32(node, "module-id", &s32MdId);
            if (s32MdId < 0) {
                os_printk("ei viss module id err:%d\n", s32MdId);
                continue;
            }
#if defined ARCH_LOMBO_N7V3
            if (s32MdId == 2) {
                Dev = 1;
            } else if (s32MdId == 4) {
                Dev = 2;
            } else {
                os_printk("ei viss module id err:%d\n", s32MdId);
            }
            os_printk("ei viss module id:%d\n", s32MdId);
#elif defined ARCH_LOMBO_N7V7
            if (s32MdId == 2) {
                Dev = 1;
            } else if (s32MdId == 3) {
                Dev = 2;
            } else {
                os_printk("ei viss module id err:%d\n", s32MdId);
            }
#endif
            of_property_read_u32(node, "i2c-bus", &s32I2cBus);
            if (s32I2cBus < 0) {
               PRT_VISS_WARN("ei viss %s i2c-bus id:%d\n", dev_name(&pdev->dev), s32I2cBus);
            }

            of_property_read_u32(node, "i2c-addr", &s32I2cAddr);
            if (s32I2cAddr < 0) {
               PRT_VISS_WARN("ei viss %s i2c-addr:0x%x\n", dev_name(&pdev->dev), s32I2cAddr);
            }

            if (!of_property_read_u32(node, "mclk", &mclk))
                vmd->stDev[Dev].u32mclk = mclk;
            else
                vmd->stDev[Dev].u32mclk = 0;

            if (!of_property_read_u32_array(node, "tp-audio", au32Audio, 4)) {
                vmd->stDev[Dev].stAudioAttr.u32SampleRate = au32Audio[0];
                vmd->stDev[Dev].stAudioAttr.u32BitWidth = au32Audio[1];
                vmd->stDev[Dev].stAudioAttr.u32ChnNum = au32Audio[2];
                vmd->stDev[Dev].stAudioAttr.u32Volume = au32Audio[3];
            }

            if (!of_property_read_u32(node, "sensor_mirror", &u32SnsMirror)) {
                vmd->stDev[Dev].u32SnsMirror = u32SnsMirror;
            }
            if (!of_property_read_u32(node, "sensor_flip", &u32SnsFlip)) {
                vmd->stDev[Dev].u32SnsFlip = u32SnsFlip;
            }

            vmd->stDev[Dev].enDevType = MCSI;
            vmd->stDev[Dev].s32MdId = s32MdId;
            vmd->stDev[Dev].u32Freq = freq;
            vmd->stDev[Dev].u32DevId = Dev;
            vmd->stDev[Dev].s32I2cBus = s32I2cBus;
            vmd->stDev[Dev].s32I2cAddr = s32I2cAddr;

            ei_viss_mcsi_init(pdev, &vmd->stDev[Dev]);
            vmd->u32DevCount++;
        } else if (!strcmp(node->name, VISS_WB_DMA_OF_NODE_NAME)) {

            ei_viss_wb_dma_init(pdev, &vmd->stWbDma);
        }

        if (vmd->u32DevCount > VISS_MAX_DEV_NUM) {
            os_printk("DEV:%d ERR!", vmd->u32DevCount);
        }
    }
    return ret;
}

int ei_viss_top_init(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    VISS_TOP_S *vmd;
    struct resource *res;
    int ret = 0;
    int i = 0;

    vmd = os_kzalloc(sizeof(*vmd), os_gfp_kernel);
    if (!vmd) {
        return -EI_FAILURE;
    }

    vmd->pdev = pdev;
    g_pstVissTop = vmd;

    for (i = 0; i < VISS_MAX_DEV_NUM; i++) {
        vmd->stDev[i].s32MdId = -1;
    }

    res = os_platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (res == EI_NULL)
    {
        os_printk("os_platform_get_resource Set Failed!\n");
        return -ENOENT;
    }

    vmd->regs = devm_ioremap_resource(dev, res);
    if (vmd->regs == EI_NULL)
    {
        os_printk("devm_ioremap_resource Set Failed!\n");
        return -ENOENT;
    }
#ifdef CONFIG_PM_GENERIC_DOMAINS

    vmd->viss_reset = platform_clk_get(pdev, 0);
    vmd->viss_gate = platform_clk_get(pdev, 1);
    vmd->viss_axi_gate = platform_clk_get(pdev, 2);
    vmd->srcclk0 = platform_clk_get(pdev, 3);
    vmd->srcclk1 = platform_clk_get(pdev, 4);

    clk_prepare_enable(vmd->viss_reset);
    ret = pm_clk_create(&pdev->dev);

    ret |= pm_clk_add_clk(&pdev->dev, vmd->viss_gate);
    ret |= pm_clk_add_clk(&pdev->dev, vmd->viss_axi_gate);
    ret |= pm_clk_add_clk(&pdev->dev, vmd->srcclk0);
    ret |= pm_clk_add_clk(&pdev->dev, vmd->srcclk1);
    pm_clk_resume(&pdev->dev);

    pm_runtime_set_active(&pdev->dev);
    /* enable pm_runtime */
    pm_runtime_enable(&pdev->dev);
#else
#ifndef CONFIG_LOMBO_DOUBLE_OS
    os_platform_clk_prepare_enable_all(pdev);
#endif
#endif

    /* clock configurations in viss top for csis/vic/isp */
    ret = ei_viss_top_config_child(vmd, dev->of_node);
    if (ret) {
        os_printk("ei_viss_top_config_child err");
    }

    platform_set_drvdata(pdev, vmd);

    return ret;
}

int ei_viss_top_exit(struct platform_device *pdev)
{
    VISS_TOP_S *vmd = platform_get_drvdata(pdev);
    int i = 0;

    os_printk("-----ei_viss_top_exit---\n");

    ei_viss_wb_dma_exit(vmd->stWbDma.pdev);

    for (i = 0; i < VISS_MAX_DEV_NUM; i++) {
        if (vmd->stDev[i].pdev != EI_NULL)
            ei_viss_dev_exit(vmd->stDev[i].pdev);
    }
#ifdef CONFIG_PM_GENERIC_DOMAINS
    pm_clk_suspend(&pdev->dev);

    pm_runtime_disable(&pdev->dev);
    pm_clk_remove(&pdev->dev, NULL);

    clk_disable_unprepare(vmd->viss_reset);
#else
    os_platform_clk_disable_unprepare_all(pdev);
#endif
    os_kfree(vmd);

    return 0;
}


static void ei_viss_set_source(void)
{
    EI_U32 i;

    for (i = 0; i < VISS_MAX_DEV_NUM; i++) {
        g_stVissSrc.as32MdId[i] = g_pstVissTop->stDev[i].s32MdId;
        g_stVissSrc.as32I2cBus[i] = g_pstVissTop->stDev[i].s32I2cBus;
        g_stVissSrc.as32I2cAddr[i] = g_pstVissTop->stDev[i].s32I2cAddr;
        g_stVissSrc.au32Freq[i] = g_pstVissTop->stDev[i].u32Freq;
        g_stVissSrc.apvDevBases[i] = g_pstVissTop->stDev[i].regs;
        g_stVissSrc.aenDevType[i] = g_pstVissTop->stDev[i].enDevType;
        g_stVissSrc.au32Mclk[i] = g_pstVissTop->stDev[i].u32mclk;
        g_stVissSrc.stAudioAttr[i] = g_pstVissTop->stDev[i].stAudioAttr;
        g_stVissSrc.au32SnsMirror[i] = g_pstVissTop->stDev[i].u32SnsMirror;
        g_stVissSrc.au32SnsFlip[i] = g_pstVissTop->stDev[i].u32SnsFlip;
#if defined ARCH_LOMBO_N7V7
        g_stVissSrc.useHfclkFlag[i] = g_pstVissTop->stDev[i].useHfclkFlag;
#endif
    }

    g_stVissSrc.pvTopBase = g_pstVissTop->regs;
    g_stVissSrc.u32DevCount = g_pstVissTop->u32DevCount;
    g_stVissSrc.pvWbDmaBase = g_pstVissTop->stWbDma.regs;
#ifdef CONFIG_LOMBO_DOUBLE_OS
    g_stVissSrc.enVissOsType = VISS_DOUBLE_OS;
#endif

}

static int ei_viss_probe(struct platform_device *pdev)
{
    EI_S32 s32Ret = EI_SUCCESS;
    struct timeval stT0;
    struct timeval stT1;
    EI_S64 Valus;
    EI_SL Valms;

    do_gettimeofday(&stT0);

    s32Ret = ei_viss_top_init(pdev);
    if (EI_SUCCESS != s32Ret)
    {
        os_printk("ei_viss_probe Failed!\n");
        return s32Ret;
    }

    ei_viss_set_source();

    VISS_ModInit();

    do_gettimeofday(&stT1);
    stT1.tv_sec = stT1.tv_sec - stT0.tv_sec;
    stT1.tv_usec = stT1.tv_usec - stT0.tv_usec;
    Valus = (EI_S64)(stT1.tv_sec * 1000000 + stT1.tv_usec);
    Valms = (EI_SL)Valus;
    Valms = Valms / 1000;

    os_printk("ei_viss_probe end! %ld ms\n", Valms);

    return s32Ret;
}

static int ei_viss_remove(struct platform_device *pdev)
{
    EI_S32 s32Ret = EI_SUCCESS;

    VISS_ModExit();

    s32Ret = ei_viss_top_exit(pdev);
    if (EI_SUCCESS != s32Ret)
    {
        os_printk("ei_viss_probe Failed!\n");
        return s32Ret;
    }

    os_printk("ei_viss_remove end\n");

    return s32Ret;
}

void VISS_DEV_Get_Sync(void)
{
#ifdef CONFIG_PM_GENERIC_DOMAINS
    VISS_TOP_S *vmd = g_pstVissTop;

    pm_runtime_get_sync(&vmd->pdev->dev);
#endif

    return;
}

void VISS_DEV_Put_Sync(void)
{
#ifdef CONFIG_PM_GENERIC_DOMAINS
    VISS_TOP_S *vmd = g_pstVissTop;

    pm_runtime_put_sync(&vmd->pdev->dev);
#endif

    return;
}

#ifdef CONFIG_PM_GENERIC_DOMAINS
static int ei_viss_runtime_suspend(struct device *dev)
{
    /* TODO */
    //pm_clk_suspend(dev);

    return 0;
}

static int ei_viss_runtime_resume(struct device *dev)
{
    /* TODO */
    //pm_clk_resume(dev);

    return 0;
}
#endif

#ifdef CONFIG_PM_SLEEP
static int ei_viss_suspend(struct device *dev)
{
    VISS_TOP_S *vmd = dev_get_drvdata(dev);

    VISS_Suspend();

#ifdef CONFIG_PM_GENERIC_DOMAINS
    pm_clk_suspend(dev);
    clk_disable_unprepare(vmd->viss_reset);

#else
    os_platform_clk_disable_unprepare_all(vmd->pdev);
#endif

    os_printk("ei_viss_suspend end\n");

    return 0;
}

static int ei_viss_resume(struct device *dev)
{
    VISS_TOP_S *vmd = dev_get_drvdata(dev);

#ifdef CONFIG_PM_GENERIC_DOMAINS
    clk_prepare_enable(vmd->viss_reset);
    pm_clk_resume(dev);

#else
    os_platform_clk_prepare_enable_all(vmd->pdev);
#endif

    VISS_Resume();

    os_printk("ei_viss_resume end\n");

    return 0;
}
#endif

#ifdef CONFIG_PM
static const struct dev_pm_ops ei_viss_pm_ops = {
#ifdef CONFIG_PM_GENERIC_DOMAINS
    SET_RUNTIME_PM_OPS(ei_viss_runtime_suspend, ei_viss_runtime_resume, NULL)
#endif

#ifdef CONFIG_PM_SLEEP
    SET_SYSTEM_SLEEP_PM_OPS(ei_viss_suspend, ei_viss_resume)
#endif
};
#endif

static const struct of_device_id ei_viss_match[] = {
    { .compatible = "ei, ei-viss" },
    {},
};

MODULE_DEVICE_TABLE(of, ei_viss_match);

static struct platform_driver ei_viss_driver = {
    .probe          = ei_viss_probe,
    .remove         = ei_viss_remove,
    .driver         =
    {
        .name           = "ei_viss",
        .of_match_table = ei_viss_match,
#ifdef CONFIG_PM
        .pm             = &ei_viss_pm_ops,
#endif
    },
};

#ifndef CONFIG_DEFERED_VISS_DRIVER
os_module_platform_driver(ei_viss_driver);
#else
static int ei_viss_driver_init(void)
{
	return os_platform_driver_register((void *)&ei_viss_driver);
}
#ifdef ARCH_LOMBO_N7V7
defer_core_initcall(ei_viss_driver_init);
#endif

static void __exit ei_viss_driver_exit(void)
{
	os_platform_driver_unregister((void *)&ei_viss_driver);
}
module_exit(ei_viss_driver_exit);
#endif

MODULE_LICENSE("GPL");
#endif

